package com.sunnuwell.demo.service.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.sunnuwell.demo.common.exception.AdException;
import com.sunnuwell.demo.common.utils.CommonPageAble;
import com.sunnuwell.demo.constant.Constants;
import com.sunnuwell.demo.entity.Role;
import com.sunnuwell.demo.entity.User;
import com.sunnuwell.demo.entity.UserToken;
import com.sunnuwell.demo.model.PageModel;
import com.sunnuwell.demo.repository.UserRepository;
import com.sunnuwell.demo.repository.UserTokenRepository;
import com.sunnuwell.demo.service.UserService;
import com.sunnuwell.demo.vo.UserRquest;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: entry
 * @description: 用户逻辑service
 * @author: Mr.lv
 * @create: 2019-04-24 11:40
 **/
@Service
public class UserServiceImpl implements UserService {
    private UserRepository userRepository;

    private UserTokenRepository userTokenRepository;

    private MongoTemplate mongoTemplate;

    public UserServiceImpl(UserRepository userRepository, UserTokenRepository userTokenRepository, MongoTemplate mongoTemplate) {
        this.userRepository = userRepository;
        this.userTokenRepository = userTokenRepository;
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public User findByUsername(UserRquest user) throws AdException {
        if (!user.validate()) {
            // 如果请求username为空的话，抛出一个异常
            throw new AdException(-1,Constants.ErrorMsg.REQUEST_PARAM_ERROR);
        }
        User findUser = userRepository.findByUsername(user.getUsername());
        return findUser;
    }

    @Override
    public User findUserById(String userId) {
        return userRepository.findByCid(userId);
    }

    @Override
    public void saveToken(UserToken userToken) {
        userTokenRepository.save(userToken);
    }

    @Override
    public UserToken findTokenByUid(String uid) {
        return userTokenRepository.findByUid(uid);
    }

    @Override
    public void save(UserRquest user) throws AdException {
        // 判断请求参数是否合法
        if (!user.validate()) {
            throw new AdException(-1,Constants.ErrorMsg.REQUEST_PARAM_ERROR);
        }
        // 合法执行插入操作
        userRepository.save(new User(
                user.getCid(),user.getUsername(),user.getPassword(),user.getSex(),user.getHeadImage()
                ,user.getPhone(),user.getBirthday(),user.getHobby(),user.getAddress(),user.getRoleList()
        ));
    }

    @Override
    public Page<User> findAll(UserRquest userRequest) throws AdException {
        // 判断请求参数
        if (!userRequest.validateSearch()) {
            throw new AdException(-1,Constants.ErrorMsg.REQUEST_PARAM_ERROR);
        }
        CommonPageAble pageAble = new CommonPageAble();
        PageModel pm = new PageModel();
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (!StringUtils.isEmpty(userRequest.getUsername())){
            criteria.and("username").is(userRequest.getUsername());
        }
        List<Sort.Order> orders = new ArrayList<Sort.Order>();  //排序
        // 开始页
        pm.setPagenumber(userRequest.getPageNumber());
        // 每页条数
        pm.setPagesize(userRequest.getPageSize());
        orders.add(new Sort.Order(Sort.Direction.DESC,"birthday"));
        Sort sort = new Sort(orders);
        // 排序
        pm.setSort(sort);
        pageAble.setPage(pm);
        query.addCriteria(criteria);
        Long count = mongoTemplate.count(query, User.class);
        // 查询
        List<User> list = mongoTemplate.find(query.with(pageAble), User.class);

        // 将集合与分页结果封装
        Page<User> pagelist = new PageImpl<User>(list, pageAble, count);
        return pagelist;
    }

    @Override
    public void update(UserRquest user) throws AdException {
        if (!user.validateAll()) {
            throw new AdException(-1,Constants.ErrorMsg.REQUEST_PARAM_ERROR);
        }
        userRepository.save(new User(
                user.getCid(),user.getUsername(),user.getPassword(),user.getSex(),user.getHeadImage()
                ,user.getPhone(),user.getBirthday(),user.getHobby(),user.getAddress(),user.getRoleList()
        ));
    }

    @Override
    public void deleteUser(UserRquest userRequest) {
        User user = new User();
        user.setCid(userRequest.getCid());
        userRepository.delete(user);
    }

    @Override
    public User checkUserToken(String token) throws AdException {
        // 执行认证
        // 1.检测user_token的有效性
        if (token == null || !token.startsWith("Bearer ")) {
            throw new AdException(402,"无token，请重新登录");
        }
        // 获取 token 中的 user id
        final String finaloken = token.substring(7);
        String userId;
        try {
            userId = JWT.decode(finaloken).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new AdException(402,"无token，请重新登录");
        }
        // 将token和redis中的token对比(暂时用数据库代替)
        UserToken userToken = this.findTokenByUid(userId);
        if (userToken == null || !userToken.getToken().equals(finaloken)) {
            throw new AdException(403,"token已经失效");
        }
        // 2.更新user_token 的过期时间（延期，保证其有效期内连续操作不掉线)
        User user = this.findUserById(userId);
        if (user == null) {
            throw new AdException(404,"用户不存在，请重新登录");
        }
        // 验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(finaloken);
        } catch (JWTVerificationException e) {
            throw new AdException(403,"token已经失效");
        }
        return user;
    }

    @Override
    public List<Role> findAllRoles() {
        List<Role> roleList = mongoTemplate.find(new Query(), Role.class);
        return roleList;
    }

    @Override
    public List<User> findAllUser() {
        return userRepository.findAll();
    }


}